﻿using MediatR;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Sgr.Application;
using Sgr.Application.Commands;
using Sgr.Generator;
using Sgr.Identity;
using Sgr.Identity.Services;
using Sgr.Indentity.Application.ViewModels;
using Sgr.Indentity.Utilities;
using System;
using System.Security.Claims;
using System.Threading;
using System.Threading.Tasks;

namespace Sgr.Indentity.Application.Commands
{
    /// <summary>
    /// 登录命令处理基类，提供通用的登录命令处理功能
    /// </summary>
    public abstract class LoginCommandHandleBase : IdentityCommandHandleBase
    {
        /// <summary>
        /// 身份验证选项
        /// </summary>
        protected readonly IdentityOptions _identityOptions;

        /// <summary>
        /// 签名验证器
        /// </summary>
        protected readonly ISignatureChecker _signatureChecker;

        /// <summary>
        /// 字符串ID生成器
        /// </summary>
        protected readonly IStringIdGenerator _stringIdGenerator;

        /// <summary>
        /// 日志记录器
        /// </summary>
        protected readonly ILogger _logger;

        /// <summary>
        /// 构造函数
        /// </summary>
        protected LoginCommandHandleBase(
            IAccountAuthService accountService,
            IHttpContextAccessor httpContextAccessor,
            ISignatureChecker signatureChecker,
            IStringIdGenerator stringIdGenerator,
            IOptions<IdentityOptions> options,
            ILogger logger)
            : base(accountService, httpContextAccessor)
        {
            _identityOptions = options?.Value ?? throw new ArgumentNullException(nameof(options));
            _signatureChecker = signatureChecker ?? throw new ArgumentNullException(nameof(signatureChecker));
            _stringIdGenerator = stringIdGenerator ?? throw new ArgumentNullException(nameof(stringIdGenerator));
            _logger = logger ?? throw new ArgumentNullException(nameof(logger));
        }

        /// <summary>
        /// 生成访问令牌
        /// </summary>
        protected string GenerateAccessToken(Account account)
        {
            string jti = _stringIdGenerator.GenerateUniqueId();
            var claims = GetClaims(jti, account);
            return CreateAccessToken(claims, _identityOptions.JWT);
        }

        /// <summary>
        /// 生成刷新令牌
        /// </summary>
        protected async Task GenerateRefreshTokenAsync(Account account, CancellationToken cancellationToken)
        {
            string newRefreshToken = _stringIdGenerator.GenerateUniqueId();
            string clientIpAddress = _httpContextAccessor?.HttpContext?.GetClientIpAddress() ?? string.Empty;

            // 创建刷新令牌并写入数据库
            await _accountService.CreateRefreshTokenAsync(
                account.Id,
                newRefreshToken,
                string.Empty,
                _identityOptions.JWT.RefreshTokenExpireMinutes,
                clientIpAddress,
                cancellationToken);

            // 写入Cookie
            WriteRefreshTokenToCookie(
                _httpContextAccessor?.HttpContext?.Response,
                newRefreshToken,
                _identityOptions.JWT);
        }

        /// <summary>
        /// 获取登录错误消息
        /// </summary>
        protected string GetLoginErrorMessage(AccountLoginResults loginResult)
        {
            return loginResult switch
            {
                AccountLoginResults.IsDeactivate => "账号已被禁用，请联系管理员",
                AccountLoginResults.IsDelete => "账号已被冻结，如有疑问请联系管理员",
                AccountLoginResults.IsLock => "账号已被锁定，请稍后重试",
                AccountLoginResults.WrongPassword or AccountLoginResults.NotExist => "账号或密码错误，请重试",
                AccountLoginResults.Success => "登录成功",
                _ => "未知的登录结果，请稍后重试"
            };
        }

        /// <summary>
        /// 验证图像验证码
        /// </summary>
        protected bool ValidateImageVerificationCode(string code, string hash, string logIdentifier)
        {
            if (!_identityOptions.UseCaptcha)
                return true;

            if (string.IsNullOrWhiteSpace(code) || string.IsNullOrWhiteSpace(hash))
                return false;

            if (hash != ImageSharpCaptchaHelper.BuildCaptchaCode(code))
            {
                _logger.LogWarning("登录请求验证码验证失败. 用户: {LoginName}", logIdentifier);
                return false;
            }

            return true;
        }

        /// <summary>
        /// 验证签名
        /// </summary>
        protected bool ValidateSignature(string signature, string timestamp, string nonce,
            string customParameters, string secretKey, string logIdentifier)
        {
            if (!_identityOptions.UseSignature)
                return true;

            if (string.IsNullOrWhiteSpace(signature) ||
                string.IsNullOrWhiteSpace(timestamp) ||
                string.IsNullOrWhiteSpace(nonce))
            {
                return false;
            }

            if (!_signatureChecker.VerifySignature(
                signature,
                timestamp,
                nonce,
                customParameters,
                secretKey))
            {
                _logger.LogWarning("登录请求签名验证失败. 用户: {Identifier}", logIdentifier);
                return false;
            }

            return true;
        }

        /// <summary>
        /// 处理验证和生成令牌的通用逻辑
        /// </summary>
        protected async Task<CommandResult<TokenViewModel>> ProcessLoginResultAsync(
            Tuple<AccountLoginResults, Account?> accountResult,
            string loginName,
            AccountLoginWay loginWay,
            CancellationToken cancellationToken)
        {
            var (loginResult, account) = accountResult;

            string displayName = account?.DisplayName ?? string.Empty;

            // 账号验证失败处理
            if (loginResult != AccountLoginResults.Success || account == null)
            {
                string errorMessage = GetLoginErrorMessage(loginResult);
                //if (account == null)
                //    errorMessage = "无法验证用户身份信息";

                await CreateLoginLogAsync(
                    account?.Id ?? string.Empty,
                    loginName,
                    displayName,
                    loginWay,
                    false,
                    errorMessage,
                    account?.OrgId ?? string.Empty,
                    cancellationToken);

                return CommandResult.Invalid<TokenViewModel>(errorMessage);
            }

            // 生成访问令牌
            var accessToken = GenerateAccessToken(account);

            // 生成刷新令牌
            await GenerateRefreshTokenAsync(account, cancellationToken);

            // 记录登录日志
            await CreateLoginLogAsync(
                account?.Id ?? string.Empty,
                loginName,
                displayName,
                loginWay,
                true,
                string.Empty,
                account?.OrgId ?? string.Empty,
                cancellationToken);

            // 返回成功结果
            return CommandResult.Success(new TokenViewModel
            {
                AccessToken = accessToken,
                ExpireSeconds = _identityOptions.JWT.ExpireSeconds
            });
        }
    }
}